/**
 * Proyecto X Tecnologia de programacion  2do cuatrimestre de 2012
 * @author
 * German Rickert LU: 93284
 * Maximiliano Tiberi LU: 83600
 * Sebastian Larrieu LU: 94056
 */


package logica;

import grafica.Panta;
import entidades.*;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Random;
import java.util.concurrent.ConcurrentLinkedQueue;

import javax.swing.Timer;


public class Juego implements Runnable {	
	
	//Atributos de jugabilidad
	protected int puntos;
	protected int vidas;
	protected int plata;
	protected  ConcurrentLinkedQueue<Marvel> marvels;
	protected LinkedList<Capcom> capcoms;
	protected LinkedList<Moneda> monedas;
	
	//Tablero del juego
	protected Tablero tablero;
	
	//interfaz grafica
	protected Panta lienzo;
	
	//Manejo de temporizadores
	protected Timer tCrear;
	protected Timer tMoneda;

	
	//boolean para evitar ConcurrentModificationException
	private boolean crear;
	private boolean accion;
	private boolean moneda;
	private boolean chequear;

	
	//Hilos del juego
	private Thread hilo;
	private Thread hilo_Marvel_Monedas;
	private boolean jugando;
	
	
	
	//Ola de Capcoms
	private OlaCapcoms ola;
	
	
	
	//Constructor
	public Juego()
	{	
		
		puntos = 0;
		vidas = 3;
		plata = 500;
		this.marvels = new  ConcurrentLinkedQueue<Marvel>();
		this.capcoms = new LinkedList<Capcom>();
		this.monedas = new LinkedList<Moneda>();
		tablero=new Tablero();
		this.crearTimers();
		informe.setFlag(false);
		

	}

	
	/**
	 * Crea el hilo del juego y da inicio a los temporizadores.
	 */
	public void inicializarJuego(int dificultad)
	{ 	
		ola = new OlaCapcoms(dificultad);
		jugando=true;
		hilo=new Thread(this);
	    crearHilo_Marvel_Monedas();
	    hilo_Marvel_Monedas.start();
	    hilo.start();
		tCrear.start();
		tMoneda.start();
		this.accion=true;
		this.chequear=true;
		crear=false;
		moneda=false;
	
	}
	
	


	/**
	 * Creacio de temporizadores que manejaran la creacion y acciones de juego
	 */
	private void crearTimers()
	{
		tCrear = new Timer (12000, new ActionListener () 
		{ 
		    public void actionPerformed(ActionEvent e) 
		    { 
		        crear=true;
		     } 
		});
		
		
		
		tMoneda = new Timer (15000, new ActionListener () 
		{ 
		    public void actionPerformed(ActionEvent e) 
		    { 
		        moneda = true;
		     } 
		});
		
				
	}
	
	/**
	 * creo un hilo para la accion de los marvel
	 */
	private void crearHilo_Marvel_Monedas()
	{
		hilo_Marvel_Monedas = new Thread() 
		{
			public void run()
			{
				while(jugando)
				{
					ataqueMarvel();	
					if(moneda)
					{	
						moneda=false;
						crearMoneda();
					}
					
				}
			}//run
			
		};			
	}

	
	/**
	 * Hilo continuo de ejecucion
	 */
	public void run()
	{
		
		while(jugando) {//ciclo del juego
			
			if(crear)
			{
				crear=false;
				this.crearCapcom();
			}
			
			if(this.accion)
			{
				this.accion=false;
				this.accionCapcom();				
			}
			
						
			if(chequear)
			{
				chequear=false;
				this.chequearMuertos();//controla que no existan personajes con vida nula en el juego.
			}
			
									
		}
			
    }
	


		

	

	/**
	 * crea un personaje aleatorio en una posicion aleatoria de la pantalla
	 */
	private void crearCapcom()
	{	
		//Para ver cuando termina el arreglo de capcoms.
		if(ola.getIndex() < ola.getTamano()){
		
		int aux=ola.getNumeroCapcom();
		ola.incrementarIndex();
		
		chequear=false;
		Random rnd=new Random();
		int f= rnd.nextInt(5);
		Posicion p =new Posicion(f,10);
		Capcom c=null;
		Capcom c1= null;
		
		switch(aux)
		{
		 case 0: 
		 		 {
			 		c= new Ryu(p);
			 		this.capcoms.addLast(c);
			 		break;
		 		 }
		 case 1: 
		 		{
		 			c= new StriderHiryu(p);
		 			this.capcoms.addLast(c);
		 			break;
		 		}
		 case 2: 
		 		{
		 			c= new Zangief(p);
		 			this.capcoms.addLast(c);
		 			break;
		 		}
		 case 3: 
		 		{
		 			c= new MegaMan(p);
		 			this.capcoms.addLast(c);
		 			informe.mostrar("cree megaman");
		 			break;
		 		}
		 		
		 case 4: 
		 		{
		 			c=new Blanka(p);
		 			if(f<=3)
		 				c1= new MiniBlanka(new Posicion(f+1,10));
		 			else
		 				c1= new MiniBlanka(new Posicion(f-1,10));
		 			this.capcoms.addLast(c);
		 			this.capcoms.addLast(c1);
		 			break;
		 		}
		 case 5:
		 		{
		 			//Salta creacion.
		 			break;
		 		}
		 }//end switch
		if(c1!= null)
		{
			lienzo.iniciarPosicion(c1);
			c1.start();  
			tablero.ubicarCapcom(c1);		
		}
		if (c != null){
			lienzo.iniciarPosicion(c);
			c.start();  
			tablero.ubicarCapcom(c);
		}
		
		chequear=true;
		}//Termino la ola
		
		else{
			tCrear.stop();
			crear=false;
		}
	}
	
	/**
	 * Crea un marvel en una posicion determinada.
	 */
	public void crearMarvel(int f, int c, int aux){
		
		Casillero cas=tablero.getCasillero(f, c);
		if(aux !=0 && !cas.hayMarvel()){//hay un boton seleccionado y no hay marvel creado en ese lugar
			
			Posicion pos= new Posicion(f,c);
			chequear= false;
			Marvel m= null;
		
		
			switch(aux)
			{
			case 1: 
		 		 	{
		 		 		m= new IronMan(pos);
		 		 		this.marvels.add(m);
		 		 		break;
		 		 	}
			case 2: 
		 			{
		 				m= new Venom(pos);
		 				this.marvels.add(m);
		 				break;
		 			}
			case 3: 
		 			{
		 				m= new Spiderman(pos);
		 				this.marvels.add(m);
		 				break;
		 			}
			case 4: 
		 			{
		 				m= new Thor(pos);
		 				this.marvels.add(m);
		 				break;
		 			}
		 			
			case 5: 
		 			{
		 				m=new Hulk(pos);
		 				this.marvels.add(m);
		 				break;
		 			}
			}//end switch
			tablero.ubicarMarvel(m);
			lienzo.iniciarPosicion(m);
			
			plata -= m.getPrecio();
			lienzo.actualizarMonedas();
		
			chequear= true;
		}//end if
	}
	
	/**
	 * crear una moneda en una posicion aleatorio.
	 */
	private void crearMoneda()
	{
		Random rnd=new Random();
		int f= rnd.nextInt(5);
		int c= rnd.nextInt(8)+1;
		Posicion p =new Posicion(f,c);
		int v= rnd.nextInt(10)+1;
		Moneda creada=new Moneda(v*50,p);
		this.monedas.addFirst(creada);
		tablero.ubicarMoneda(creada);
		lienzo.crearMoneda(creada);
	}
	

	/**
	 * Ola de accion capcom
	 */
	private void accionCapcom()
	{	
		chequear= false;
		Casillero cas, cas1;
		
		for( Capcom c : capcoms )
		{	
			if(c.getAccion() && !(c.getAtacando()))
			{	
				if ( c.getPosicion().getColumna()==0)
				{	

                    lienzo.removerEntidad(c);
                    this.restarVida();
                    lienzo.actualizarVidas();
                    c.recibirAtaque(200);
                    tablero.retirarCapcom(c);
					
				}
				else //no llegue al final
				{
					cas = tablero.siguiente(c);
					informe.mostrar("Mi posicion es: "+c.getPosicion().getColumna());
					if(cas.hayMarvel() )
					{
						c.setEnemigo(cas.getMarvel());
						c.setAccion(false);
						informe.mostrar("accion="+c.getAccion());
						c.setAtacando(true);
						informe.mostrar("atacando="+c.getAtacando());
						
						if(c.salta())//si tengo la habilidad de saltar
						{	Posicion p = c.getPosicion();
							cas1= tablero.getCasillero(p.getFila(), p.getColumna());
							cas1.removerCapcom(c);
							p.setColumna(p.getColumna()-1);		
							tablero.ubicarCapcom(c);
							c.setAccion(false);
							c.setEnemigo(cas.getMarvel());
							c.setAtacando(true);
						}
					}
					else//no llegue al final y no hay enemigos
					{
						
						Posicion p = c.getPosicion();
						cas1= tablero.getCasillero(p.getFila(), p.getColumna());
						cas1.removerCapcom(c);
						p.setColumna(p.getColumna()-1);		
						tablero.ubicarCapcom(c);
						c.setAccion(false);
						informe.mostrar("cambie de posicion logica");
						
					}
				
				}
		  }
		
		}//for each capcom
         
		this.accion=true;
		chequear= true;
	}
	

	
	/**
	 * ola de ataque marvel
	 */
	private void ataqueMarvel()
	{
		chequear= false;

		for(Marvel m :this.marvels)//para cada marvel
			{
				if(m.getAccion())//si es su turno de atacar
				{	
					m.setAccion(false);
					m.getGrafica().setImagenAcutal(1);
					try {
						m.sleep(2000);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					m.getGrafica().setImagenAcutal(0);
					
					Disparo d = m.atacar();
					for(Posicion p : d.getPosiciones())//reviso su rango de ataque
					{	
						Casillero cas= tablero.getCasillero(p.getFila(),p.getColumna());
						if(cas.hayCapcom())
							{	
								lienzo.mostrarDisparo(d, p);
								this.atacarTodos(cas, d.getPoder());
								
								
							}
					}//for-each posicion
				}//getAccion
			}//for-each marvel
	
		chequear= true;
	}
	
	/** ataca todos los capcom de un casillero
	 *@param c casillero a atacar 
	 */
	private void atacarTodos(Casillero c, int p)
	{
		for(Capcom cap : c.getCapcom())
		{	
			
				cap.recibirAtaque(p);
		}//for-each capcom
	}
	
	/**
	 * chequea si hay personajes con vida nula y los elimina del juego.
	 */
	private void chequearMuertos() 
	{	
		
		Iterator<Capcom> it = capcoms.iterator();
		while(it.hasNext())
		{
			Capcom c = it.next();
			if(c.getVida()<=0)
				{
					this.eliminarCapcom(c);
					it.remove();
				}
		}
		
								
			
		Iterator<Marvel> itm= marvels.iterator();
		while(itm.hasNext())
		{
			Marvel m = itm.next();
			if(m.getVida()<=0)
				{
					lienzo.removerEntidad(m);
					tablero.retirarMarvel(m);
					itm.remove();
				}
		}
		 if(capcoms.isEmpty() && ola.getIndex()==1)
         {
       	  this.finDeJuego();
         }
		chequear=true;
		
		
		
	}

	/**
     * elimina un capcom del juego cuando es derrotado
     * @param c
     */
  private void eliminarCapcom(Capcom c)
  {
	  if(c.getPosicion().getColumna() > 0){
          int puntos = c.getPuntaje();
          aumentarPuntaje(puntos);
          lienzo.actualizarPuntaje();
	  }
          lienzo.removerEntidad(c);
          tablero.retirarCapcom(c);
         
  }

	
	/**
	 * resta una vida y chequea si queda alguna
	 */
	private void restarVida()
	{
		vidas--;
		if (vidas == 0)
		 {
				finDeJuego();
		 }
	}
	
	/**
	 * aumenta los puntos del jugador
	 * @param p puntos
	 */
	private void aumentarPuntaje(int p)
	{
		puntos = puntos + p;
		lienzo.actualizarPuntaje();
	}
	
	/**
	 * Remueve la moneda clickeada y aumenta las disponibles.
	 * @param m moneda
	 */
		
	public void removerMoneda(Moneda m)
	{
		plata+=m.getValor();
		lienzo.actualizarMonedas();
		lienzo.actualizarBotones();
		tablero.retirarMoneda(m);
		monedas.remove(m);
	}
	
	/**
	 * le da la pantalla al juego.
	 * @param p
	 */
	public void setPantalla(Panta p)
	{
		lienzo=p;
	}
	
	
	/**
	 * termina la ejecucion del hilo de juego y los temporizadores.
	 */
	private void finDeJuego()
	{	
		tCrear.stop();
		jugando=false;
		lienzo.pantallaFinal();
		hilo=null;
	}



	//Consultas
	/**
	 * cantidad de vidas restantes.
	 * 
	 */
	public int getVidas(){
		return vidas;
	}
	
	/**
	 * cantidad de monedas disponibles.
	 * 
	 */
	public int getMonedas()
	{
		return plata;
	}
	
	/**
	 * puntos del jugador
	 * 
	 */
	public int getPuntaje()
	{
		return puntos;
	}
	
	

}
